#include "HC_SR04_Config.h"
#include "TIM_Config.h"

/* 全局变量定义 ------------------------------------------------------------*/
volatile float Distance = 0.0;  
// 作用：存储最终测量的距离值（单位：厘米）
// volatile关键字作用：
// 1. 保证变量在中断和主程序间可见性
// 2. 防止编译器优化导致读取脏数据
// 3. 确保每次访问都从内存读取最新值

/* 私有函数声明 ------------------------------------------------------------*/
static void Open_HCSR04_TIM(void);   // 内部函数：启动定时器测量
static void Close_HCSR04_TIM(void);  // 内部函数：停止定时器测量
static u32 Get_Echo_Timer(void);     // 内部函数：计算回波高电平持续时间

/**
    ******************************************************************************
    * @brief  HC-SR04硬件初始化函数
    * @param  无
    * @retval 无
    * @说明   完成以下硬件初始化：
    *         1. 使能GPIOB时钟（Trig和Echo引脚所在端口）
    *         2. 配置Trig引脚为推挽输出模式
    *         3. 配置Echo引脚为下拉输入模式
    *         4. 初始化TIM4定时器（1ms周期）
    ******************************************************************************
*/
void HC_SR04_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    
    // 使能GPIOB时钟（必须使能时钟才能配置对应引脚）
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* 配置Trig引脚（PB5）参数说明：
       - GPIO_Mode_Out_PP：推挽输出模式
       - GPIO_Speed_50MHz：最大输出速度50MHz
       - 初始状态设为低电平（保证模块初始不触发） */
    GPIO_InitStruct.GPIO_Pin = HC_SR04_TRIG_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(HC_SR04_TRIG_PORT, &GPIO_InitStruct);
    GPIO_ResetBits(HC_SR04_TRIG_PORT, HC_SR04_TRIG_PIN);

    /* 配置Echo引脚（PB6）参数说明：
       - GPIO_Mode_IPD：下拉输入模式（默认低电平）
       - 无上拉电阻，依赖模块内部驱动 */
    GPIO_InitStruct.GPIO_Pin = HC_SR04_ECHO_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(HC_SR04_ECHO_PORT, &GPIO_InitStruct);

    // 初始化TIM4定时器（配置为1ms周期）
    // 注：TIM4_Config()的具体实现需在TIM_Config.h中查看
    TIM4_Config(1);
}

/**
    ******************************************************************************
    * @brief  发送超声波触发脉冲
    * @param  无
    * @retval 无
    * @工作流程：
    *         1. Trig引脚输出20us高电平脉冲
    *         2. 自动恢复低电平
    * @硬件要求：
    *         - 触发脉冲宽度必须≥10us（实际用20us保证可靠性）
    *         - 两次触发间隔建议≥60ms
    ******************************************************************************
*/
void HC_SR04_Start(void)
{
    // 发送高电平触发脉冲（20us）
    GPIO_SetBits(HC_SR04_TRIG_PORT, HC_SR04_TRIG_PIN);
    Delay_us(20);  // 精确延时20微秒
    GPIO_ResetBits(HC_SR04_TRIG_PORT, HC_SR04_TRIG_PIN);
}

/**
    ******************************************************************************
    * @brief  启动定时器测量回波时间
    * @param  无
    * @retval 无
    * @操作说明：
    *         1. 清零TIM4计数器
    *         2. 清零毫秒计数器
    *         3. 使能TIM4定时器
    ******************************************************************************
*/
static void Open_HCSR04_TIM(void)
{
    TIM_SetCounter(TIM4, 0);  // 计数器归零
    ms_HcSR04_Count = 0;     // 溢出次数计数器归零
    TIM_Cmd(TIM4, ENABLE);   // 启动定时器
}

/**
    ******************************************************************************
    * @brief  停止定时器测量
    * @param  无
    * @retval 无
    * @操作说明：
    *         1. 关闭TIM4定时器
    *         2. 保持当前计数值不变
    ******************************************************************************
*/
static void Close_HCSR04_TIM(void)
{
    TIM_Cmd(TIM4, DISABLE);  // 停止定时器
}

/**
    ******************************************************************************
    * @brief  计算回波高电平持续时间
    * @param  无
    * @retval 高电平持续时间（单位：微秒）
    * @计算公式：
    *         总时间 = 溢出次数×1000 + 当前计数值
    * @注意事项：
    *         1. 调用后会自动重置计数器
    *         2. 包含50ms延时等待模块稳定
    ******************************************************************************
*/
static u32 Get_Echo_Timer(void)
{
    u32 time_us = ms_HcSR04_Count * 1000;  // 将毫秒转换为微秒
    time_us += TIM_GetCounter(TIM4);       // 加上当前微秒级计数值
    TIM4->CNT = 0;                         // 计数器手动复位
    Delay_ms(50);                          // 等待模块稳定
    return time_us;
}

/**
    ******************************************************************************
    * @brief  获取5次测量的平均距离
    * @param  无
    * @retval 距离值（单位：厘米）
    * @测量流程：
    *         1. 发送触发脉冲
    *         2. 等待回波信号上升沿
    *         3. 启动定时器计时
    *         4. 等待回波信号下降沿
    *         5. 停止定时器并计算单次距离
    *         6. 重复5次后取平均值
    * @距离换算公式：
    *         距离(cm) = 高电平时间(us) / 58
    *         物理原理：声速343m/s → 每微秒传播0.0343cm（往返需÷2）
    *         推导过程：t(us)×0.0343/2 ≈ t/58
    ******************************************************************************
*/
float HCSR04_Get_Distance(void)
{
    u32 echo_time = 0;  // 单次测量时间值
    float sum = 0.0;    // 5次测量累加和
    
    // 进行5次测量取平均值
    for(u8 i=0; i<5; i++){
        HC_SR04_Start();              // 发送触发脉冲
        while(!HC_SR04_ECHO_Read());  // 等待回波高电平开始
        Open_HCSR04_TIM();            // 启动计时
        while(HC_SR04_ECHO_Read());   // 等待高电平结束
        Close_HCSR04_TIM();           // 停止计时
        echo_time = Get_Echo_Timer(); // 获取高电平持续时间
        sum += (float)echo_time / 58.0f;  // 时间换算为距离（单位：cm）
    }
    
    // 计算5次测量平均值
    Distance = sum / 5.0f;
    return Distance;
}
